<?php
/**
 * Copyright (c) 2006-2008, Julien PORTALIER
 * http://featherphp.googlecode.com/
 * 
 * Some functions are derived from CakePHP,
 * Copyright (c) 2006, Cake Software Foundation, Inc.
 * http://cakephp.org/
 * 
 * Licensed under The MIT License
 * Redistributions of files must retain the above copyright notice.
 */

/**
 * Returns true if a variable is an associative array.
 * 
 * @return Boolean
 * @param $arr Mixed
 */
function is_hash(&$arr)
{
	if (is_array($arr))
	{
		foreach(array_keys($arr) as $k)
		{
#			if (!is_integer($k))
#				return true;
			if (is_integer($k))
				return false;
		}
		return true;
	}
	return false;
}

/**
 * Sanitizes an array by removing magic quotes.
 * 
 * Eg: cleanArray($_GET);
 * 
 * @deprecated Set 'magic_quotes_gpc' to false in php.ini.
 */
function & cleanArray(&$a)
{
#	if (get_magic_quotes_gpc())
		__cleanArray($a);
	return $a;
}

function __cleanArray(&$a)
{
	if (is_array($a))
	{
		foreach(array_keys($a) as $k)
			__cleanArray($a[$k]);
	}
	else
	{
		$a = stripslashes($a);
	}
}

function implode_with_keys($sep1, $sep2, array $arr)
{
	foreach($arr as $k => $v) {
		$arr[$k] = "$k$sep2$v";
	}
	return implode($sep1, $arr);
}

/**
 * Computes the intersection of arrays by comparing keys.
 */
function & array_intersect_keys(array $arr, array $keys)
{
	$rs = array();
	foreach($arr as $k => $v)
	{
		echo $k;
		if (in_array($k, $keys)) {
			$rs[$k] = $v;
		}
	}
	return $rs;
}

/**
 * Merges arrays recursively.
 * 
 * @return Array Merged array.
 * @param $arr1 Array
 * @param $arr2 Array
 */
function & array_recursive_merge(array $arr1, array $arr2)
{
	$arrays = func_get_args();
	$left   = array_shift($arrays);
	
	while(!empty($arrays))
	{
		$right = array_shift($arrays);
		foreach($right as $k => $v)
		{
			foreach ($v as $kk => $vv) {
				$left[$k][$kk] = $vv;
			}
		}
	}
	return $left;
}

/**
 * Permits to work with lists in array or string (comma separated) forms.
 * 
 * @return Array
 * @param $arr   Mixed Array or String.
 * @param $split String Token separator(s).
 */
function array_collection($arr, $split=',;')
{
	if (!is_array($arr)) {
		$arr = preg_split('/['.preg_quote($split).']/', $arr, -1, PREG_SPLIT_NO_EMPTY);
	}
	foreach($arr as $k => $v)
	{
		$v = trim($v);
		
		if (empty($v)) {
			unset($arr[$k]);
		}
		else {
			$arr[$k] = $v;
		}
	}
	$arr = array_unique($arr);
	return $arr;
}

/**
 * Will print out any PHP variable.
 * @todo Use var_dump instead of print_r?
 */
function debug()
{
	if (!DEBUG)
		return;
	foreach (func_get_args() as $v)
	{
		echo '<pre>';
		print_r($v);
		echo '</pre>';
	}
}

/**
 * Logs a record into a file.
 */
function file_log($text, $log='default')
{
	Load::libs('log');
	Log::instance()->write($text, $log);
}

/**
 * Caches data, or reads data from cache if not outdated. 
 * 
 * @param  $path    string Cached file.
 * @param  $data    string Data to be cached (null if reading).
 * @param  $expires mixed  Cached data lifetime.
 * @param  $target  string cache|public|apc Save cached file in app/empt/cache, app/webroot or in memory?
 * @return string cached data or false.
 */
function cache($path, $data=null, $expires=null, $target='cache')
{
	if (is_null($expires))
		$expires = Core::cache_lifetime;
	
	switch (strtolower($target))
	{
		case 'cache':
			$filename = CACHE.$path;
			break;
		
		case 'public':
			$filename = APP.'webroot'.DS.$path;
			break;
	}
	
	if (is_null($data))
	{
		# read cache from file
		if (file_exists($filename))
		{
			$now = time();
			if (is_string($expires))
				$expires = strtotime($expires);
			if (filemtime($filename) + ($expires - $now) < $now)
			{
				# cache has expired
				@unlink($filename);
				return false;
			}
			else
			{
				# cache is good!
				return unserialize(file_get_contents($filename));
			}
		}
	}
	else
	{
		# save cache into file
		return file_put_contents($filename, serialize($data), LOCK_EX);
	}
	
	return false;
}

/**
 * Caches data in memory, or reads data from memory cache (if not outdated),
 * falls back on filecache if PHP-APC isn't present.  
 * 
 * @param  $path    String  Cached file.
 * @param  $data    String  Data to be cached (null if reading).
 * @param  $expires Mixed   Cached data lifetime.
 * @return String  Cached data or false.
 * 
 * @todo Add support for XCache (?)
 */
function memory_cache($path, $data=null, $expires=null)
{
	if (is_null($expires))
		$expires = Core::cache_lifetime;
	
	# if APC is present:
	if (function_exists('apc_fetch'))
	{
		$key = CACHE.$path;
		if (is_null($data))
		{
			# read cache
			$data = apc_fetch($key);
			return ($data !== false) ? unserialize($data) : false;
		}
		else
		{
			# save cache
			if (is_string($expires))
				$expires = strtotime($expires);
			return apc_store($key, serialize($data), $expires);
		}
	}
	
	# fallback on filecache
	return cache($path, $data, $expires, 'cache');
}

/**
 * Finds a file that can exists in different extensions.
 * Eg: an image file in JPEG, PNG or GIF format.
 * 
 * @return Mixed Full path to file, or null. 
 * @param $path String Full path to file.
 * @param $extensions String Comma separated list of possible extensions.
 */
function get_image($path, $extensions='gif,jpg,png')
{
	$files = glob($path.'.{'.$extensions.'}', GLOB_NOSORT | GLOB_BRACE);
	return isset($files[0]) ? $files[0] : null;
}

/**
 * vsprintf like, but with named parameters.
 * 
 * Contrary to the original vsprintf it won't do any typecasting,
 * special formating, etc. It relies on PHP's toString conversion.
 * It's preliminary meant to be used in translation strings.
 * 
 * \code
 * $str = vsprint("Hello, my name is {name}!\n", array('name' => 'Julien'));
 * \endcode
 */
function vsprint($str, array $params)
{
	foreach($params as $k => $v) {
		$str = str_replace('{'.$k.'}', $v, $str);
	}
	return $str;
}

/**
 * vprintf like, but with named parameters.
 * 
 * Contrary to the original vsprintf it won't do any typecasting,
 * special formating, etc. It relies on PHP's toString conversion.
 * It's preliminary meant to be used in translation strings.
 * 
 * \code
 * vprint("Hello, my name is {name}!\n", array('name' => 'Julien'));
 * \endcode
 */
function vprint($str, array $params)
{
	echo vsprint($str, &$params);
}

?>